﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.AdoNet;
using NHibernate.Connection;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Mapping.ByCode;
using NHibernate;

namespace Bizbase.Repository.Nhibernate
{
    public class DatabaseBuilder
    {
        private NHibernate.Cfg.Configuration _config;
        private ISessionFactory _sessionFactory;

        public DatabaseBuilder(DatabaseType dbType, string connectionString)
        {
            _config = new NHibernate.Cfg.Configuration();

            BuildConfiguration(dbType, connectionString);
        }

        private void BuildConfiguration(DatabaseType dbType, string connectionString)
        {
            if (dbType == DatabaseType.Oracle)
            {
                _config.DataBaseIntegration(db =>
                {
                    db.Dialect<Oracle10gDialect>();
                    db.Driver<OracleDataClientDriver>();
                    db.Batcher<OracleDataClientBatchingBatcherFactory>();
                    db.BatchSize = 200;
                });
            }
            else if (dbType == DatabaseType.SqlServer)
            {
                _config.DataBaseIntegration(db =>
                {
                    db.Dialect<MsSql2008Dialect>();
                    db.Driver<Sql2008ClientDriver>();
                    db.Batcher<SqlClientBatchingBatcherFactory>();
                    db.BatchSize = 200;
                });
            }
            else if (dbType == DatabaseType.SQLite)
            {
                _config.DataBaseIntegration(db =>
                {
                    db.Dialect<SQLiteDialect>();
                    db.Driver<SQLite20Driver>();
                });
            }

            _config.DataBaseIntegration(db =>
            {
                db.ConnectionProvider<DriverConnectionProvider>();
                db.ConnectionString = connectionString;
                //db.Timeout = (byte)timeout;
            });
        }

        public void AddMappings(IEnumerable<Type> types)
        {
            ModelMapper mapper = new ModelMapper();
            mapper.AddMappings(types);

            var hbmMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();

            _config.AddMapping(hbmMapping);
        }

        public void AddMapping<T>() where T : IConformistHoldersProvider, new()
        {
            ModelMapper mapper = new ModelMapper();
            mapper.AddMapping<T>();

            var hbmMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();

            _config.AddMapping(hbmMapping);
        }

        public void BuildSchema()
        {
            SchemaExport se = new SchemaExport(_config);
            se.Execute(false, true, false);
        }

        public ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    _sessionFactory = _config.BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }
    }
}
